"""
加密算法
"""
import base64
import hashlib
import hmac
import subprocess
from functools import partial

from Crypto.Cipher import DES,AES
from Crypto.Util.Padding import pad, unpad

subprocess.Popen = partial(subprocess.Popen, encoding='utf-8')  #在导入execjs前加入补丁 解决js编码字符集问题

import execjs

"""
MD5
MD5 一种被广泛使用的密码散列函数,可以产生出一个128位(16 字节)的散列值(hash value）用于确保信息传输完整一致。
MD5 加密算法是不可逆的，所以解密一般都是通过暴力穷举方法，以及网站的接口实现解密。

配置js环境：
在对应文件的项目文件夹中下载所需要的库

js可以通过crypto-js来实现
需要先在node.js解释器中安装第三方模式（驱动）crypto-js（加密算法库==》里面提供所有的加密算法）
安装命令：npm install 模块名 --registry https://registry.npmmirror.com/
查看npm的所有第三方模块命令：npm list

特征：
长度为32的16进制的数字字母

对于js逆向来说关键点是找到text

常用关键字md5|MD5
"""
# text = 'xunter勋特'
# #js版本：
# js_data = """
# const CryptoJs = require('crypto-js')
# function test(text){
#     return CryptoJs.MD5(text).toString();
# }
# """
# js = execjs.compile(js_data)
# res = js.call('test',text)
# print(res)
#
# # python版本
# h = hashlib.md5()   # 创建对象
# h.update(text.encode()) #传入参数
# res = h.hexdigest() #编码
# print(res,len(res))


"""
SHA1

SHA1 安全哈希算法主要适用于数字签名标准 里面定义的数字签名算法 SHA1 比 MD5 的安全性更强。
对于长度小于 2^64 位的消息， SHA1 会产生一个 160 位的消息摘要。
一般在未高度混淆的 Js 代码中， SHA1 加密的关键词就是 Sha1。


"""
# text = 'xunter勋特'
# #js版本：
# js_data = """
# const CryptoJs = require('crypto-js')
# function test(text){
#     return CryptoJs.SHA1(text).toString();
# }
# """
# js = execjs.compile(js_data)
# res = js.call('test',text)
# print(res)
#
# python版本
text = '226816516'
h = hashlib.sha1()   # 创建对象
h.update(text.encode()) #传入参数
res = h.hexdigest() #编码
print(res,len(res))

"""
HMAC 散列消息鉴别码
HMAC 加密算法是一种安全的基于加密hash函数和 共享密钥 的消息认证协议。 
实现原理是用公开函数和密钥产生一个固定长度的值作为 认证标识,用这个标识鉴别消息的完整性。

关键词：
hex，HmacSHA256

特征：
长度为64的16进制的数字字母
"""
# # 找text和key
# key = 'xunter'  #密钥
# text = 'xunter勋特'
# #js版本：
# js_data = """
# const CryptoJs = require('crypto-js')
# function test(text,key){
#     let hash = CryptoJs.HmacSHA256(text,key)
#     return CryptoJs.enc.Hex.stringify(hash)
# }
# """
# js = execjs.compile(js_data)
# res = js.call('test',text,key)
# print(res)
#
# # # python版本
# h = hmac.new(key.encode(),text.encode(),hashlib.sha256)   # 创建对象
# res = h.hexdigest() #编码
# print(res,len(res))


"""
DES 数据加密标准 属于对称加密算法。 
DES 是一个分组加密算法,典型的 DES 以 64 位为分组对数据加密,加密和解密用的是同一个算法。 
它的密钥长度是 56 位 (因为每个第 8 位都用作奇偶校验), 密钥可以是任意的 56 位数， 而且可以任意时候改变。

关键字：des，mode，padding
得到text和iv填充 知道了加密模式和填充模式
"""
# key = '12345678'
# text = 'xunter勋特'
# iv = '12345678'
# # js版本
# js_data = """
# const CryptoJs = require('crypto-js')
# function test(text, key, iv){
#     key = CryptoJs.enc.Utf8.parse(key) // 转字节数组
#     text = CryptoJs.enc.Utf8.parse(text)
#     cfg = {
#         iv: CryptoJs.enc.Utf8.parse(iv),
#         mode: CryptoJs.mode.CBC,
#         padding: CryptoJs.pad.Pkcs7 //填充模式
#     }
#     return CryptoJs.DES.encrypt(text,key,cfg).toString();
# }
# """
# js = execjs.compile(js_data)
# res = js.call('test', text, key, iv)
# print(res)
# #
# # python版本
# DES_dict = DES.new(key=key.encode(), mode=DES.MODE_CBC, iv=iv.encode())  # 创建加密对象
# pad_data = pad(text.encode(), DES.block_size)  # 填充字符串数据
# DES_en = DES_dict.encrypt(pad_data)  # 加密
# res = base64.b64encode(DES_en).decode()  # base64转换，转字符串
# print(res, len(res))
#
# # 解密使用和加密一样的密钥
# DES_dict = DES.new(key=key.encode(), mode=DES.MODE_CBC, iv=iv.encode())  # 创建加密对象
# b64_de_date = base64.b64decode(res)
# DES_de = DES_dict.decrypt(b64_de_date)
# unpad_data = unpad(DES_de, DES.block_size)
# print(unpad_data.decode())

"""
AES 高级加密标准 
在密码学中又称 Rijndael 加密法,是美国联邦政府采用的一种区块加密标准。 
AES 也是对称加密算法， 如果能够获取到密钥， 那么就能对密文解密。 
AES 填充模式常用的有三种， 分别是 NoPadding、 ZeroPadding、 Pkcs7， 默认为 Pkcs7.

Js 逆向时， AES 加密的搜索关键词有 AES、 mode、 padding 等

AES 填充模式常用的有三种， 分别是 NoPadding、 ZeroPadding、 Pkcs7， 默认为 Pkcs7

"""

# # 密钥与填充为16位
# key = '1234567809abcdef'
# text = 'xunter勋特'
# iv = '1234567809abcdef'
# # js版本
# js_data = """
# const CryptoJs = require('crypto-js')
# function test(text, key, iv){
#     key = CryptoJs.enc.Utf8.parse(key) // 转字节数组
#     text = CryptoJs.enc.Utf8.parse(text)
#     cfg = {
#         iv: CryptoJs.enc.Utf8.parse(iv),
#         mode: CryptoJs.mode.CBC,
#         padding: CryptoJs.pad.Pkcs7 //填充模式
#     }
#     return CryptoJs.AES.encrypt(text,key,cfg).toString();
# }
# """
# js = execjs.compile(js_data)
# res = js.call('test', text, key, iv)
# print(res)
# #
# # python版本
# 加密
# AES_dict = AES.new(key=key.encode(), mode=AES.MODE_CBC, iv=iv.encode())  # 创建加密对象
# pad_data = pad(text.encode(), AES.block_size)  # 填充字符串数据
# AES_en = AES_dict.encrypt(pad_data)  # 加密
# res = base64.b64encode(AES_en).decode()  # base64转换，转字符串
# print(res, len(res))
#
# # 解密使用和加密一样的密钥
# AES_dict = AES.new(key=key.encode(), mode=AES.MODE_CBC, iv=iv.encode())  # 创建加密对象
# b64_de_date = base64.b64decode(res)
# AES_de = AES_dict.decrypt(b64_de_date)
# unpad_data = unpad(AES_de, AES.block_size)
# print(unpad_data.decode())
